home *** CD-ROM | disk | FTP | other *** search
/ The 640 MEG Shareware Studio 2 / The 640 Meg Shareware Studio CD-ROM Volume II (Data Express)(1993).ISO / clang / asm4.zip / WAITASEC.ASM < prev   
Assembly Source File  |  1986-02-05  |  15KB  |  450 lines

  1. ;    WAITASEC.ASM -- Holds and Recalls Scrolling Screens
  2. ;    ============
  3. ;            (C) Copyright Charles Petzold, 1985
  4. ;
  5. ;            COM file format
  6. ;
  7.  
  8. CSEG        Segment
  9.         Assume    CS:CSEG
  10.         Org    0080h
  11. SWAP        Label    Byte        ; Use this area for line swapping
  12.         Org    0100h
  13. Entry:        Jmp    Initialize    ; Entry: Jump over resident part
  14.  
  15. ;    All Data
  16. ;    --------
  17.  
  18. Cols        equ    80        ; You may want to set this to 40
  19. ScrollLock    equ    70        ; Scan code of Scroll Lock key
  20. NumberOfScreens    dw    8        ; Can be set up to 15 for 80-column
  21.  
  22.         db    '(C) Copyright Charles Petzold, 1985'
  23.  
  24. DisplaySegment    dw    ?        ; Display address set by VideoCheck
  25. OldInterrupt9    dd    ?         ; Saved address of real Interrupt 9
  26. OldInterrupt10    dd    ?        ; Ditto for Interrupt 10h
  27.  
  28. TopHoldAddr    dw    Offset HoldArea    ; Address of top of Hold area
  29. BotHoldAddr    dw    ?        ; Address of bottom of Hold area
  30. SavePointer    dw    Offset HoldArea ; Points to where text is saved
  31. RecallPointer    dw    Offset HoldArea    ; Points to where text is recalled
  32.  
  33. LockStateOn    db    0        ; Flag for lock or no lock
  34. ScrollLockDown    db    0        ; Current state of Scroll Lock key
  35.  
  36. KeyDispatch    dw    Home,Up,PgUp    ; Dispatch addresss of routines
  37.         dw    5 Dup (Dummy)    ; for cursor movement within
  38.         dw    End,Down,PgDn    ; recalled displays
  39.  
  40. ;    Intercept of Interrupt 10h -- BIOS Video Call
  41. ;    --------------------------
  42.  
  43. NewInterrupt10:    Cmp    AX,0601h    ; Check if this is a 1 line scroll up
  44.         Jne    NoNeedToBother    ; No, just continue to real interrupt
  45.         Cmp    CX,0        ; Check if this is upper left corner
  46.         Jne    NoNeedToBother    ; No, don't want to touch it
  47.         Cmp    DL,Cols - 1    ; Check if DL is right hand side
  48.         Jne    NoNeedToBother    ; Another obstacle that shuts us out    
  49.         Call    VideoCheck    ; Returns Carry if graphics
  50.         Jc    NoNeedToBother    ; So we drop out here if Carry is set
  51.  
  52.         Sti            ; Allow interrupts
  53.         Cld            ; And set direction to forward
  54.         Push    CX        ; Save all the registers we'll use 
  55.         Push    SI
  56.         Push    DI
  57.         Push    DS
  58.         Push    ES
  59.  
  60.         Push    CS            ; Push this code segment
  61.         Pop    ES            ; So we can set ES to it
  62.         Mov    DI,CS:[SavePointer]    ; This is the destination
  63.         Mov    DS,CS:[DisplaySegment]    ; This is the source segment
  64.         Sub    SI,SI            ; Source is top of display
  65.         Mov    CX,Cols            ; The number of characters
  66.  
  67.         Call    VideoOff        ; Turn off light show if color
  68.         Rep    Movsw            ; Move 'em in!
  69.         Call    VideoOn            ; Turn display back on
  70.  
  71.         Cmp    DI,CS:[BotHoldAddr]    ; Check the new destination
  72.         Jb    NotAtBotYet        ; Jump if it hasn't wrapped yet
  73.         Mov    DI,CS:[TopHoldAddr]    ; Set it to top if it has
  74. NotAtBotYet:    Mov    CS:[SavePointer],DI    ; And save it anyway
  75.         
  76.         Pop    ES            ; Pop the registers we saved 
  77.         Pop    DS
  78.         Pop    DI
  79.         Pop    SI
  80.         Pop    CX
  81.  
  82. NoNeedToBother:    Jmp    CS:[OldInterrupt10]    ; And do the interrupt for real
  83.  
  84. ;    Intercept of Interrupt 9h -- Hardware Keyboard Interrupt
  85. ;    --------------------------------------------------------    
  86.  
  87. NewInterrupt9:    Sti            ; Allow other interrupts
  88.         Push    AX        ; Save the register for awhile
  89.         In    AL,60h        ; Get the pressed key scan code
  90.         Cmp    AL,ScrollLock    ; Check if it's the Scroll Lock
  91.         Jz    GottaScrollLock    ; If so, do special routine
  92.         Cmp    AL,128 + ScrollLock    ; Check if scroll lock release
  93.         Jz    ScrollLockRlse    ; Another special routine
  94.         Jmp    AnyOtherKey    ; Otherwise, it's some other key
  95.  
  96.                         ; Scroll Lock key depressed
  97.                         ; -------------------------
  98.  
  99. GottaScrollLock:Mov    CS:[ScrollLockDown],1    ; Flag Scroll Lock as depressed
  100.         Cmp    CS:[LockStateOn],1    ; See if we're locked now
  101.         Jz    AnyOtherKey        ; If so, will just reset
  102.  
  103.         Mov    AH,2            ; Do keyboard interrupt
  104.         Int    16h            ;   to get shift states
  105.         Test    AL,04            ; See if Ctrl has been pressed
  106.         Jnz    NormalProcess        ; Process normally if Break
  107.  
  108.         Call    VideoCheck        ; See if video is OK for recall
  109.         Jc    NormalProcess        ; If not, ignore the key
  110.  
  111.         Mov    CS:[LockStateOn],1    ; Lock state now ON
  112.         Push    CS:[SavePointer]    ; Transfer value of SavePointer
  113.         Pop    CS:[RecallPointer]    ; ... to RecallPointer 
  114.         PushF                ; Simulate an interrupt
  115.         Call    CS:[OldInterrupt9]    ; Let Scroll Lock Register
  116.         Call    VideoOn            ; Video might be off - turn on
  117.  
  118. HoldingPattern:    Cmp    CS:[LockStateOn],1    ; Wait in this loop ...
  119.         Jz    HoldingPattern        ; ... until out of lock state 
  120.  
  121.         Jmp    NormalProcess        ; Then process last key
  122.  
  123.                         ; Scroll Lock key released
  124.                         ; ------------------------
  125.  
  126. ScrollLockRlse:    Mov    CS:[ScrollLockDown],0    ; Register Scroll Lock release
  127.         Cmp    CS:[LockStateOn],1    ; See if in lock state
  128.         Jnz    NormalProcess        ; If not, just process key
  129.  
  130.         Mov    AX,CS:[SavePointer]    ; Check if the screen is in
  131.         Cmp    AX,CS:[RecallPointer]    ;   normal position
  132.         Jnz    NormalProcess        ; If not, just process key
  133.  
  134.         Mov    CS:[LockStateOn],0    ; If so, turn lock state OFF
  135.         Pop    AX            ; Restore register
  136.         IRet                ; Return to holding pattern
  137.  
  138.                         ; All other keys
  139.                         ; --------------
  140.  
  141. AnyOtherKey:    Cmp    CS:[LockStateOn],1    ; For other keys, just do
  142.         Jnz    NormalProcess        ; normal processing if not lock
  143.  
  144.         Call    NowInLockState        ; But call routine if locked
  145.         Pop    AX            ; Restore register
  146.         IRet                ; Return to holding pattern
  147.  
  148. NormalProcess:    Pop    AX            ; Get back the register
  149.         Jmp    CS:[OldInterrupt9]    ; Let the key process
  150.  
  151. ;    Routine for other keys during lock state (AL = Scan Code)
  152. ;    ---------------------------------------------------------
  153.  
  154. NowInLockState:    Cld            ; String moves generally forward
  155.         Push    CX        ; We use all these registers
  156.         Push    DX
  157.         Push    SI 
  158.         Push    DI
  159.         Push    DS
  160.         Push    ES
  161.  
  162.         Mov    DX,CS            ; Get value of CS    
  163.         Mov    DS,DX            ; Set DS and
  164.         Mov    ES,DX            ; ES to this segment
  165.         Assume    DS:CSEG, ES:CSEG    ; And tell the assembler     
  166.  
  167.         Mov    AH,AL            ; AH is actual scan code
  168.         And    AL,7Fh            ; AL has release byte off
  169.  
  170.         Sub    AL,71            ; Subtract the 'Home' key value
  171.         Jb    WrongKey        ; No good if below
  172.         Cmp    AL,(81 - 71)        ; Above the 'PgDn' key?
  173.         Ja    WrongKey        ; You're not right either
  174.         Cmp    AL,(73 - 71)        ; Check if under or = 'PgUp'
  175.         Jbe    AllRightKey        ; Ok for this key
  176.         Cmp    AL,(79 - 71)        ; Check if over or = 'End'
  177.         Jae    AllRightKey        ; You pass too
  178.  
  179. WrongKey:    Cmp    [ScrollLockDown],1    ; See if scroll lock is down
  180.         Jz    ResetKeyboard        ; If so, just ignore the key
  181.  
  182.         Call    End            ; If not, restore the display
  183.         Mov    [LockStateOn],0        ; Turn off the lock state
  184.         Jmp    KeyReturn        ; And get out quickly    
  185.  
  186. AllRightKey:    Test    AH,80h            ; See if cursor key is release
  187.         Jnz    ResetKeyboard        ; If so, ignore the key
  188.  
  189.         Cbw                ; Convert scan code to word    
  190.         Add    AX,AX            ; Double it because word access
  191.         Mov    SI,AX            ; Set SI to it
  192.         Call    [KeyDispatch + SI]    ; And do the routine
  193.  
  194. ResetKeyboard:    In    AL,61h            ; These instructions
  195.         Mov    AH,AL            ; reset the keyboard
  196.         Or    AL,80h
  197.         Out    61h,AL
  198.         Mov    AL,AH
  199.         Out    61h,AL
  200.  
  201.         Cli                ; Disable interrupts
  202.         Mov    AL,20h            ; to reset the interrupt
  203.         Out    20h,AL            ; controller
  204.         
  205. KeyReturn:    Pop    ES            ; Get back all the pushes
  206.         Pop    DS
  207.         Pop    DI
  208.         Pop    SI
  209.         Pop    DX
  210.         Pop    CX
  211.         Ret                ; Return to previous routine
  212.  
  213. ;    Routines to scan up through saved display
  214. ;    -----------------------------------------
  215.  
  216. Home:        Mov    CX,0FFFFh    ; 'Home' key -- "infinite" lines up
  217.         Jmp    Short GoingUp    ; Do it
  218.  
  219. Up:        Mov    CX,1        ; 'Up' key -- 1 line up
  220.         Jmp    Short GoingUp    ; Go to it
  221.  
  222. PgUp:        Mov    CX,25        ; 'PgUp' key -- 25 lines (1 screen) up    
  223.  
  224. GoingUp:    Mov    AX,[RecallPointer]    ; Points to the text source
  225.         Cmp    AX,[TopHoldAddr]    ; Check if it's at the top
  226.         Ja    NotScanUpTop        ; If not there, no problem
  227.         Mov    AX,[BotHoldAddr]    ; Otherwise must wrap around
  228. NotScanUpTop:    Sub    AX,Cols * 2        ; Go back one line for recall
  229.         Cmp    AX,[SavePointer]    ; Check if cycled through yet
  230.         Je    EndGoingUp        ; If so, abort this routine
  231.  
  232.         Mov    [RecallPointer],AX    ; Save the new pointer value
  233.         Push    CX            ; And save our counter
  234.  
  235.         Mov    SI,2 * 24 * Cols    ; Set source to bottom line
  236.         Call    DisplayToSwap        ; Transfer it to SWAP area 
  237.     
  238.         Mov    SI,2 * 24 * Cols - 2    ; End of penultimate line 
  239.         Mov    DI,2 * 25 * Cols - 2    ; End of last line
  240.         Std                ; Backwards string transfer
  241.         Call    ScrollDisplay        ; Do the screen scroll
  242.         Cld                ; Direction back to forward
  243.  
  244.         Mov    DI,0            ; Destination is top line
  245.         Call    HoldToDisplay        ; Move line to display
  246.         Call     SwapToHold        ; And SWAP line to hold
  247.  
  248.         Pop    CX            ; Get back the counter
  249.         Loop    GoingUp            ; And do CX times
  250.  
  251. Dummy:                        ; Should never get here
  252. EndGoingUp:    Ret                ; But this is the end
  253.  
  254. ;    Routines to scan down through saved display
  255. ;    -------------------------------------------
  256.  
  257. End:        Mov    CX,0FFFFh    ; 'End' key -- infinite lines down
  258.         Jmp    Short GoingDown    ; Do it
  259.  
  260. Down:        Mov    CX,1        ; 'Down' key -- 1 line down    
  261.         Jmp    Short GoingDown    ; All ready
  262.  
  263. PgDn:        Mov    CX,25        ; 'PgDn' key -- 25 lines down
  264.  
  265. GoingDown:    Mov    AX,[RecallPointer]    ; Check if all through
  266.         Cmp    AX,[SavePointer]    ; by this comparison
  267.         Je    EndGoingDown        ; If so, exit this thing
  268.  
  269.         Push    CX            ; Save the counter
  270.         
  271.         Mov    SI,0            ; Set source to top line
  272.         Call    DisplayToSwap        ; Transfer it to SWAP area
  273.     
  274.         Mov    SI,2 * 80        ; Source is second line
  275.         Mov    DI,0            ; Destination is top line
  276.         Call    ScrollDisplay        ; So we can scroll up display
  277.  
  278.         Mov    DI,2 * 24 * Cols    ; Destination is bottom line    
  279.         Call    HoldToDisplay        ; For the saved text
  280.         Call    SwapToHold        ; Move original top line in
  281.  
  282.         Mov    AX,[RecallPointer]    ; Adjust the recall pointer
  283.         Add    AX,Cols * 2        ; By increasing by one line
  284.         Cmp    AX,[BotHoldAddr]    ; See if wrap around
  285.         Jb    NotScanDownBot        ; If not, skip a little
  286.         Mov    AX,[TopHoldAddr]    ; Get the top address
  287. NotScanDownBot:    Mov    [RecallPointer],AX    ; And set to new recall
  288.  
  289.         Pop    CX            ; Get back the counter
  290.         Loop    GoingDown        ; Do this CX times
  291.  
  292. EndGoingDown:    Ret                ; Go back to caller
  293.  
  294. ;    Display to Swap -- Save top or bottom line of display (SI) in SWAP area
  295. ;    -----------------------------------------------------------------------
  296.  
  297. DisplayToSwap:    Push    DS            ; Save data segment     
  298.         Mov    DS,[DisplaySegment]    ; And set it to display
  299.         Mov    DI,Offset Swap        ; This is the destination
  300.         Mov    CX,Cols            ; Do one line
  301.         Call    VideoOff        ; Turn off color video
  302.         Rep    Movsw            ; Do the line move
  303.         Pop    DS            ; Get back DS
  304.         Ret                ; And end
  305.  
  306. ;    Scroll Video Display -- SI is source, DI destination
  307. ;    ----------------------------------------------------
  308.  
  309. ScrollDisplay:    Push    DS            ; Save both these segments
  310.         Push    ES
  311.         Mov    ES,[DisplaySegment]    ; Set both to display
  312.         Mov    DS,[DisplaySegment]
  313.         Mov    CX,24 * Cols        ; 24 lines must be moved
  314.         Rep    Movsw             ; This line does it
  315.         Pop    ES            ; Get back the segments
  316.         Pop    DS
  317.         Ret                ; And go back
  318.  
  319. ;    Hold To Display -- Move one saved line to video display (DI)
  320. ;    ------------------------------------------------------------
  321.  
  322. HoldToDisplay:    Push    ES            ; Now save just ES
  323.         Mov    ES,[DisplaySegment]    ; And set it to display
  324.         Mov    SI,[RecallPointer]    ; This is the source
  325.         Mov    CX,Cols            ; One line only
  326.         Rep    Movsw            ; Do the transfer
  327.         Call    VideoOn            ; Color display back on
  328.         Pop    ES            ; Get back ES
  329.         Ret                ; And return
  330.  
  331. ;    Swap To Hold -- Completes the cycle
  332. ;    -----------------------------------
  333.  
  334. SwapToHold:    Mov    SI,Offset Swap        ; Source is SWAP
  335.         Mov    DI,[RecallPointer]    ; Destination in HoldArea 
  336.         Mov    CX,Cols            ; One line transfer
  337.         Rep    Movsw            ; Do it
  338.         Ret                ; And return
  339.  
  340. ;    Video Check -- Returns CY flag is graphics or 40 column or not page 0
  341. ;    ---------------------------------------------------------------------
  342.  
  343.         Assume    DS:Nothing, ES:Nothing 
  344.  
  345. VideoCheck:    Push    AX
  346.         Push    BX
  347.  
  348.         Mov    CS:[DisplaySegment],0B000h    ; Set up for monochrome
  349.  
  350.         Mov    AH,15            ; Get current video mode
  351.         Int    10h            ;   through display interrupt
  352.  
  353.         Cmp    AL,7            ; See if monochrome
  354.         Jz    VideoAOK        ; If so, skip out OK
  355.         Cmp    AL,3            ; Check if it's graphics
  356.         Ja    VideoNoGood        ; If so, can't do anything
  357.         Cmp    BH,0            ; Check if it's Page 0
  358.         Jnz    VideoNoGood        ; Nope?  No bad
  359.         Cmp    AH,Cols            ; See if columns is right
  360.         Jne    VideoNoGood        ; No -- dishonorable discharge
  361.  
  362.         Mov    CS:[DisplaySegment],0B800h    ; Change it to color
  363. VideoAOK:    Clc                ; Flag for no error
  364.         Jmp    Short VideoReturn    ; Get out
  365. VideoNoGood:    Stc                ; Flag for error
  366. VideoReturn:    Pop    BX            ; Get back register
  367.         Pop    AX
  368.         Ret                ; Now go back 
  369.  
  370. ;    Video Off -- Turns off display for Color / Graphics
  371. ;    ---------------------------------------------------
  372.  
  373. VideoOff:    Cmp    CS:[DisplaySegment],0B800h    ; Check if color 
  374.         Jnz    NoColorTurnOff            ; If not, punt
  375.  
  376.         Push    AX            ; Just use two registers
  377.         Push    DX
  378.         Mov    DX,3DAh            ; Color / Graphics Status Port
  379.  
  380. RetraceWait1:    In    AL,DX            ; Get Color / Graphics Status
  381.         Test    AL,08            ; Check the vertical retrace
  382.         Jnz    RetraceWait1        ; Loop till it's over
  383.  
  384. RetraceWait2:    In    AL,DX            ; Check status again
  385.         Test    AL,08            ; In particular the retrace
  386.         Jz    RetraceWait2        ; Loop till it comes
  387.  
  388.         Mov    DX,3D8h            ; Video Mode Select 
  389.         Mov    AL,25h            ; Byte to turn off video
  390.         Out    DX,AL            ; Turn it off
  391.  
  392.         Pop    DX            ; Retrieve registers from stack
  393.         Pop    AX
  394. NoColorTurnOff:    Ret
  395.  
  396. ;    Video On -- Turns Color Display back on
  397. ;    ---------------------------------------
  398.  
  399. VideoOn:    Cmp    CS:[DisplaySegment],0B800h    ; See if color
  400.         Jnz    NoColorTurnOn            ; If not do nothing
  401.  
  402.         Push    AX            ; Save registers
  403.         Push    DX
  404.  
  405.         Mov    DX,3D8h            ; Video mode register port
  406.         Mov    AL,28h - (Cols EQ 80)    ; i.e., 29h for 80 columns
  407.         Out    DX,AL            ; Turn video back on
  408.  
  409.         Pop    DX            ; Get back registers
  410.         Pop    AX
  411. NoColorTurnOn:    Ret                ; And leave
  412.  
  413. ;    Initialization Procedure
  414. ;    ------------------------
  415.  
  416.         Assume    DS:CSEG, ES:CSEG
  417.  
  418. HoldArea    Label    Word            ; Storage of screens also
  419.  
  420. Initialize:    Mov    AX,Cols * 25 * 2    ; Characters per screen 
  421.         Mul    [NumberOfScreens]    ; AX = bytes for HoldArea
  422.         Add    AX,Offset HoldArea    ; Calculate bottom of HoldArea
  423.         Mov    [BotHoldAddr],AX    ; Save the bottom address
  424.         Mov    DX,AX            ; Last address for terminate
  425.  
  426.         Sub    AX,AX            ; Zero out AX
  427.         Mov    DS,AX            ; To set DS to Vector Segment
  428.  
  429.         Cli                ; No Interrupts now
  430.  
  431.         Les SI,DS:[9h * 4]            ; Get Int 9 address
  432.         Mov Word Ptr CS:[OldInterrupt9],SI        ; Save offset
  433.         Mov Word Ptr CS:[OldInterrupt9 + 2],ES        ; Save segment
  434.         Mov Word Ptr DS:[9h * 4],Offset NewInterrupt9    ; New offset
  435.         Mov Word Ptr DS:[9h * 4 + 2],CS            ; New segment
  436.  
  437.         Les SI,DS:[10h * 4]            ; Get Int 10 address
  438.         Mov Word Ptr CS:[OldInterrupt10],SI        ; Save offset
  439.         Mov Word Ptr CS:[OldInterrupt10 + 2],ES        ; Save segment
  440.         Mov Word Ptr DS:[10h * 4],Offset NewInterrupt10    ; New offset
  441.         Mov Word Ptr DS:[10h * 4 + 2],CS        ; New segment
  442.  
  443.         Sti                ; Interrupts back on
  444.  
  445.         Int    27h            ; Terminate and stay resident
  446.  
  447. CSEG        EndS                
  448.  
  449.         End Entry            ; End denotes Entry point
  450.